package com.wjw.java.oop.polymorphic_;

/**
 *
 * 对象的多态：一个对象有多种形态,如：我是在家是孩子的爸爸、在单位是公司的员工...
 * --------------------------------------------------------------------------
 * 1.多态的前提条件：类的继承extends,接口的实现类implements
 *
 * 2.代码中多态的体现：父类的引用指向子类对象、接口的引用指向接口的实现类
 * 格式1：父类 对象名  = new 子类();
 *      Father father = new Son();
 * 格式2：接口 接口名 = new 实现类();
 *      UserService uService = new UserServiceImpl();
 *
 * 3.多态向上转型：父类的引用指向子类对象
 *   父类 对象名  = new 子类();
 *
 * 4.多态向上转型规则
 *  多态形式访问成员变量：①编译时看=左边，②运行时也看=左边
 *  多态形式访问成员方法：①编译时看=左边，②运行时看=右边
 *
 * 5.多态向下转型：
 *   子类 对象名 = (子类) 父类的引用
 *
 * 6.多态向下转型规则：
 *  只能强转为父类的引用,不能强转为父类的对象,强转后编译类型和运行类型都为子类
 *  Son son = (Son) father; 正确,此时编译类型和运行类型都为Son
 *  Son son = (Son) Father; 错误
 *
 *  要求父类的引用必须指向的是当前目标类型的对象
 *  Father father = new Son();正确
 *  Father father = new Daughter(); 错误,运行时会报错Daughter cannot be cast to Son
 *
 *  可以调用子类中的所有成员(属性、方法)
 *
 *  7.instanceof关键字,用于判断对象的运行类型是否为XX类型或XX类型的子类,如:
 *  son instanceof Son      true
 *  son instanceof Father   true
 */
public class Polymorphic {
    public static void main(String[] args) {
        /**
         * -----------------------------------1.向上转型(start)-----------------------------------
         */
        Father father = new Son();
        //访问成员变量时：编译时看=左边,运行时也看=左边
        //编译看=左边,编译类型为Father,该类中有name属性,编译通过
        //运行看=左边,运行类型为Father,输出结果为爸爸
        System.out.println(father.name);//爸爸

        //编译看=左边,编译类型为Father,该类中有method(),编译通过
        //运行看=右边,运行类型为Son,该类中有method(),所以会调用Son中的method()
        father.method();//【子类】方法

        //编译看=左边,编译类型为Father,该类中有methodFu(),编译通过
        //运行看=右边,运行类型为Son,该类中没有methodFu(),就会往父类找,所以会调用Father中的methodFu()
        father.methodFu();//【父类】特有方法

        //编译看=左边,编译类型为Father,该类中有methodZi(),编译报错
        //father.methodZi();//编译报错

        //编译看=左边,编译类型为Father,该类中有show(),编译通过
        //运行看=右边,运行类型为Son,该类中有show(),所以会调用Son中的show()
        father.show();//儿子：son哈哈哈

        //编译看=左边,编译类型为Father,该类中有showName(),编译通过
        //运行看=右边,运行类型为Son,该类中没有showName(),就会往父类找,所以会调用Father中的showName()
        father.showName();//爸爸
        /**
         * -----------------------------------1.向上转型(end)-----------------------------------
         */
        System.out.println("-------------------------------");
        /**
         * -----------------------------------2.向下转型(start)-----------------------------------
         */
        Son son = (Son) father;
        System.out.println(son.name);//儿子
        son.method();//【子类】方法
        son.methodFu();//【父类】特有方法
        son.methodZi();//【子类】特有方法
        son.show();//儿子：son哈哈哈
        son.showName();//爸爸
        /**
         * -----------------------------------2.向下转型(end)-----------------------------------
         */
        System.out.println("-------------------------------");
        /**
         * -----------------------------------3.instanceof关键字-----------------------------------
         */
        System.out.println(son instanceof Son);//true
        System.out.println(son instanceof Father);//true
    }
}
//父类
class Father{
    String name = "爸爸";
    public void method(){
        System.out.println("【父类】方法");
    }
    public void methodFu(){
        System.out.println("【父类】特有方法");
    }
    public void show(){
        System.out.println(name+"：father哈哈哈");
    }
    public void showName(){
        System.out.println(this.name);
    }
}
//儿子
class Son extends Father{
    String name = "儿子";
    @Override
    public void method(){
        System.out.println("【子类】方法");
    }
    public void methodZi(){
        System.out.println("【子类】特有方法");
    }
    @Override
    public void show(){
        System.out.println(name+"：son哈哈哈");
    }
}
//女儿
class Daughter extends Father{

}